/**
 * 使用信号量，同步进程
 *  对同一块内存进行操作
*/

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/sem.h>

union semun {
    int val;
    struct semid_ds *buf;
    ushort *array;
};

int main()
{

    key_t key = (key_t)20;
    int shmid;
    if ((shmid = shmget(key, 100, IPC_CREAT | S_IRUSR | S_IWUSR)) < 0)
    {
        perror("shmget error: ");
        exit(EXIT_FAILURE);
    }

    int *p = shmat(shmid, NULL, 0);
    *p = 10000;

    int semid;
    if ((semid = semget(key, 1, IPC_CREAT | S_IRUSR | S_IWUSR)) < 0)
    {
        perror("semget error: ");
        exit(EXIT_FAILURE);
    }

    union semun semun;
    semun.val = 1;
    if (semctl(semid, 0, SETVAL, semun) < 0)
    {
        perror("semctl error: ");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (0 > pid)
    {
        perror("fork error: ");
        exit(EXIT_FAILURE);
    }
    else if (0 < pid)
    {
        struct sembuf spos = {0, -1, SEM_UNDO};
        if (semop(semid, &spos, 1) < 0)
        {
            perror("semop error: ");
            exit(EXIT_FAILURE);
        }

        *p -= 9000;
        printf("%lx val = %d\n", (long unsigned int)getpid(), *p);

        spos.sem_op = 1;
        if (semop(semid, &spos, 1) < 0)
        {
            perror("semop error: ");
            exit(EXIT_FAILURE);
        }

        wait(0);
    }
    else
    {
        struct sembuf spos = {0, -1, SEM_UNDO};

        if (semop(semid, &spos, 1) < 0)
        {
            perror("semop error: ");
            exit(EXIT_FAILURE);
        }

        *p -= 2000;
        printf("%lx val = %d\n", (long unsigned int)getpid(), *p);

        spos.sem_op = 1;
        if (semop(semid, &spos, 1) < 0)
        {
            perror("semop error: ");
            exit(EXIT_FAILURE);
        }
    }

    return 0;
}